package channelHandler

import (
	"errors"
	"gitee.com/fierce_wolf/go-fox-edge-channel-common/channelLogger"
	"gitee.com/fierce_wolf/go-fox-edge-common/commLogger"
	"gitee.com/fierce_wolf/go-fox-edge-common/commUtil/Hex"
	"gitee.com/fierce_wolf/go-fox-edge-common/commUtil/Json"
	"gitee.com/fierce_wolf/go-fox-edge-common/commUtil/Map"
	"github.com/dop251/goja"
	"go-fox-edge-channel-tcp-server-v2/channelEngine/channelManager"
	"go-fox-edge-channel-tcp-server-v2/channelEngine/channelParams"
	"go-fox-edge-channel-tcp-server-v2/channelEngine/scriptEngine"
	"net"
)

type ChannelNotify struct {
	Manufacturer string
	DeviceType   string

	KeyHandler string

	SessionHandler SessionHandler
	ManageHandler  ManageHandler
}

func (e *ChannelNotify) getServiceKey(pack []byte) (channelName, deviceKey string, channelParam map[string]interface{}, err error) {
	engine := scriptEngine.GetScriptEngine(e.Manufacturer, e.DeviceType, e.KeyHandler)
	if engine == nil {
		return "", "", nil, errors.New("未定义函数：找不到对应的【身份识别】操作keyHandler")
	}

	// 执行JSP脚本中的函数：getHeaderLength
	encode, ok := goja.AssertFunction(engine.Get("getServiceKey"))
	if !ok {
		return "", "", nil, errors.New("未定义函数：getServiceKey")
	}

	data := Hex.EncodeToString(pack)

	// 执行函数
	res, err := encode(goja.Undefined(), engine.ToValue(data))
	if err != nil {
		return "", "", nil, err
	}

	// 检查：返回的结果，格式是否正确 channelKey
	result := Json.BuildMapByJson(res.String())
	channelName = Map.GetString(result, "channelKey", "")
	if channelName == "" {
		return "", "", nil, errors.New("返回的数据格式不正确，缺失参数：channelKey")
	}

	// 检查：返回的结果，格式是否正确 deviceKey
	channelParam = Map.GetMap(result, "channelParam", make(map[string]interface{}))
	deviceKey = Map.GetString(channelParam, "deviceKey", "")
	if deviceKey == "" {
		return "", "", nil, errors.New("返回的数据格式不正确，缺失参数：deviceKey")
	}

	return channelName, deviceKey, channelParam, nil
}

func (e *ChannelNotify) ChannelActive(conn net.Conn) {
	channelManager.Insert(conn)
	commLogger.Info("连接建立: 远端设备->" + conn.RemoteAddr().String())
}

func (e *ChannelNotify) ChannelRead(conn net.Conn, data []byte) {
	// 检查：channel是否已经标识上了信息
	serviceKey := channelManager.GetServiceKeyByRemoteAddr(conn.RemoteAddr().String())
	if serviceKey == "" {
		// 从报文总获得业务特征信息
		channelName, deviceKey, channelParam, err := e.getServiceKey(data)
		if err != nil {
			channelLogger.PrintlInfoLogger("身份识别:" + conn.RemoteAddr().String() + "; 识别出错->" + err.Error())
			return
		}

		serviceKey = deviceKey

		// 标记:serviceKey信息
		channelManager.SetServiceKey(conn, serviceKey)

		// 记录接收到的报文
		channelLogger.PrintlInfoLogger("身份识别:" + conn.RemoteAddr().String() + "; serviceKey->" + serviceKey)

		// 发出创建通道的消息
		e.ManageHandler.CreateChannel(channelName, channelParam)

		// 发出创建设备的消息
		e.ManageHandler.CreateDevice(e.Manufacturer, e.DeviceType, channelName, deviceKey)
	}

	// 消息处理
	e.SessionHandler.OnMessage(conn, serviceKey, data)
}

func (e *ChannelNotify) ChannelClose(conn net.Conn) {
	// 刷新为未登录状态
	deviceKey := channelManager.GetServiceKeyByRemoteAddr(conn.RemoteAddr().String())
	channelParams.SetChannelLogin(deviceKey, false)

	commLogger.Info("连接断开: 远端设备->" + conn.RemoteAddr().String())

	channelManager.RemoveByRemoteAddr(conn.RemoteAddr().String())
}

func (e *ChannelNotify) ExceptionCaught(conn net.Conn, err error) {
	commLogger.Info("数据异常: 远端设备->" + conn.RemoteAddr().String() + ", 错误信息->" + err.Error())
}
